#include "FileLogger.h"
#ifdef WIN32
#include <shlwapi.h>
#include <time.h>
#else
#include <dirent.h>
#endif

#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>

bool isSameDay(time_t t1, time_t t2)
{
	tm tm1 = timeToTm(t1);
	tm tm2 = timeToTm(t2);
	if (tm1.tm_year == tm2.tm_year
		&& tm1.tm_yday == tm2.tm_yday)
	{
		return true;
	}
	return false;
}


void fixPath(std::string &path)
{
	if (path.empty()){ return; }
	for (std::string::iterator iter = path.begin(); iter != path.end(); ++iter)
	{
		if (*iter == '\\'){ *iter = '/'; }
	}
	if (path.at(path.length() - 1) != '/'){ path.append("/"); }
}

bool isDirectory(std::string path)
{
#ifdef WIN32
	return PathIsDirectoryA(path.c_str()) ? true : false;
#else
	DIR * pdir = opendir(path.c_str());
	if (pdir == NULL)
	{
		return false;
	}
	else
	{
		closedir(pdir);
		pdir = NULL;
		return true;
	}
#endif
}



bool createRecursionDir(std::string path)
{
	if (path.length() == 0) return true;
	std::string sub;
	fixPath(path);

	std::string::size_type pos = path.find('/');
	while (pos != std::string::npos)
	{
		std::string cur = path.substr(0, pos - 0);
		if (cur.length() > 0 && !isDirectory(cur))
		{
			bool ret = false;
#ifdef WIN32
			ret = CreateDirectoryA(cur.c_str(), NULL) ? true : false;
#else
			ret = (mkdir(cur.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0);
#endif
			if (!ret)
			{
				return false;
			}
		}
		pos = path.find('/', pos + 1);
	}

	return true;
}

FileLogger::FileLogger()
{
	m_timeLastFlush = 0;
	m_timeToday = 0;
}


FileLogger::~FileLogger()
{
}

void FileLogger::DoPrint(LogItem & li)
{
	ConsoleLogger::DoPrint(li);

	if (OpenFile())
	{
		m_File.Write(li.buffer, li.length);
		m_WriteLength += li.length;

		if (time(NULL) - m_timeLastFlush > 30) //30s flush to file
		{
			m_File.Flush();
			m_timeLastFlush = time(NULL);
		}
	}
}

bool FileLogger::OpenFile()
{
	bool sameday = isSameDay(time(NULL), m_timeToday);
	bool needChageFile = m_WriteLength > m_MaxFileSize * 1024 * 1024;

	if (!sameday || needChageFile)
	{
		if (!sameday)
		{
			m_WriteLength = 0;
			m_curIndex = 0;
			m_timeToday = time(NULL);
		}
		else if (needChageFile)
		{
			m_WriteLength = 0;
			m_curIndex ++;
		}

		m_File.Close();
	}

	if (!m_File.Opened())
	{
		tm t = timeToTm(m_timeToday);
		std::string path = m_strFilePath;

		if (path[path.length()-1] != '\\'
			|| path[path.length() - 1] != '/')
		{
			path += '/';
		}

		char buf[250] = { 0 };
		sprintf(buf, "%04d_%02d/", t.tm_year + 1900, t.tm_mon + 1);
		path += buf;

		if (!isDirectory(path))
		{
			createRecursionDir(path);
		}

		sprintf(buf, "%s_%04d%02d%02d_%03d.log",
			getLoggerName(), t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,m_curIndex);

		path += buf;
		m_File.Open(path.c_str(), "ab");
		return m_File.Opened();
	}

	return true;
}

void FileLogger::Init(const char * pszFilePath, int nMaxFileSize)
{
	if (pszFilePath != NULL)
	{
		m_strFilePath = pszFilePath;
	}
	else
	{
		m_strFilePath = "./";
	}

	m_MaxFileSize = nMaxFileSize;	
}

//////////////////////////////////////////////////////////////////////////
File::File()
{
	_file = NULL;
}

File::~File()
{
	Close();
}

bool File::Opened()
{
	return _file != NULL;
}

bool File::Open(const char *path, const char * mod)
{
	Close();

	_file = fopen(path, mod);
	return _file != NULL;
}

void File::Close()
{
	if (_file != NULL)
	{
		fclose(_file); 
		_file = NULL; 
	}
}

void File::Write(const char * data, size_t len)
{
	if (_file && len > 0)
	{
		if (fwrite(data, 1, len, _file) != len)
		{
			Close();
		}
	}
}

bool File::ReadLine(std::string & content)
{
	if (!Opened())
	{
		return false;
	}

	content.reserve(512);
	if (_file && fgets(&content[0], 512, _file) != NULL)
	{
		return true;
	}

	return false;
}

bool File::ReadAll(std::string & content)
{
	if (!Opened())
	{
		return false;
	}

	fseek(_file, 0, SEEK_SET);
	int beginpos = ftell(_file);
	fseek(_file, 0, SEEK_END);
	int endpos = ftell(_file);
	fseek(_file, 0, SEEK_SET);

	int filelen = endpos - beginpos;
	if (filelen > 10 * 1024 * 1024 || filelen <= 0)
	{
		return false;
	}

	content.reserve(filelen + 1);
	content.resize(filelen + 1, '0');

	if (fread(&content[0], 1, filelen, _file) != (size_t)filelen)
	{
		content.clear();
		return false;
	}

	return true;
}

size_t File::FileSize()
{
	if (!Opened())
	{
		return 0;
	}

	int curPos = ftell(_file);
	fseek(_file, 0, SEEK_SET);
	int beginpos = ftell(_file);

	fseek(_file, 0, SEEK_END);
	int endpos = ftell(_file);

	fseek(_file, curPos, SEEK_SET);

	return endpos - beginpos;
}

void File::Flush()
{
	if (_file) fflush(_file);
}

void File::SetFilePos(int pos)
{
	if (_file)
	{
		fseek(_file, pos, SEEK_SET);
	}
}

int File::GetFilePos()
{
	if (_file)
	{
		return ftell(_file);
	}

	return 0;
}
